package com.kd.oss.downloader;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.apache.log4j.Logger;

import com.aliyun.oss.model.OSSObjectSummary;
import com.aliyun.oss.model.ObjectListing;
import com.kd.oss.utils.OssUtils;
import com.kd.oss.utils.PropertiesUtils;

public class OssDownloader {

	private static final Logger logger = Logger.getLogger(OssDownloader.class);
	
	private static final String localDir;
	private static String nextMarker = null;
	private static final int maxKeys;
	
	static {
		Properties ossfsPro = PropertiesUtils.getProperties("ossfs.properties");
		localDir = ossfsPro.getProperty("local.dir");
		maxKeys = Integer.parseInt(ossfsPro.getProperty("oss.maxkeys", "100"));
		init();
		String tmpMarker = ossfsPro.getProperty("oss.next.marker");
		if(null!=tmpMarker && !"".equals(tmpMarker.trim())) {
			nextMarker = tmpMarker;
		}
	}
	
	public static void main(String[] args) {
//		List<String> keys = OssUtils.list("2017_04_18", maxKeys);
//		for(String key : keys) {
//			System.out.println(key);
//		}
//		
		new OssDownloader().start();
	}
	
	public void start() {
		logger.info("Start to download to the directory[" + localDir + "] from the OSS server from start marker[" + (null==nextMarker?"null":nextMarker) + "]");
		while(true) {
			String tmpMarker = download2(nextMarker, maxKeys);
			if(null == tmpMarker) {
				continue ;
			}
			if("NONE".equals(tmpMarker)) {
				//nextMarker = DateUtils.getDateStringOf8(System.currentTimeMillis());
				try {
					Thread.sleep(5000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				continue ;
			}
			nextMarker = tmpMarker;
		}
	}
	
	//initialize next marker
	public static void init() {
		String tmp = load("logs/downloader.log");
		if(null != tmp) {
			nextMarker = tmp;
			logger.info("Success to initialize the next marker[" + nextMarker + "]");
		}
	}
	
	public static void download() {
		List<String> keys = OssUtils.list();
		if(null == keys) {
			return ;
		}
		
		for(String key : keys) {
			if(OssUtils.download(key, localDir)) {
				logger.info("Success to download a file[" + key + "]");
			} else {
				logger.warn("Failed to download a file[" + key + "]");
			}
		}
	}
	
	public static String download(String marker) {
		List<String> keys = OssUtils.list(marker);
		if(null == keys) {
			return null;
		}
		String nextMarker = null;
		for(String key : keys) {
			if(OssUtils.download(key, localDir)) {
				logger.info("Success to download a file[" + key + "]");
				nextMarker = key;
			} else {
				logger.warn("Failed to download a file[" + key + "]");
			}
		}
		return nextMarker;
	}
	
	public static String download(String marker, int maxKeys) {
		List<String> keys = OssUtils.list(marker, maxKeys);
		if(null == keys) {
			return null;
		}
		logger.info("There are files number: " + keys.size() + ", to download");
		String nextMarker = null;
		for(String key : keys) {
			if(OssUtils.download(key, localDir)) {
				logger.info("Success to download a file[" + key + "]"); 
				nextMarker = key;
			} else {
				logger.warn("Failed to download a file[" + key + "]");
				break;
			}
		}
		return nextMarker;
	}
	
	public static String download2(String marker, int maxKeys) {
		ObjectListing objectListing = OssUtils.objectListing(marker, maxKeys);
		if(null == objectListing) {
			return null;
		}
		List<String> keys = new ArrayList<String>();
		if(objectListing.isTruncated()) {
	    	List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
	    	for (OSSObjectSummary s : sums) {
	//            System.out.println("\t" + s.getKey());
	            if(!s.getKey().endsWith(".txt")) {
	           	 	continue ;
	            }
	            //2017_04_18/000000061235#57637B50F52D3224F1ED26F08BE4B39E#10162.txt
	            keys.add(s.getKey());
	        }
    	}
		if(keys.isEmpty()) {
			logger.info("There is no any files to download, Please wait for 5 second...");
			return "NONE";
		}
		logger.info("There are files number: " + keys.size() + ", to download");
		if(download(keys, localDir)) {
			logger.info("Success to convert nextMarker[" + objectListing.getNextMarker() + "]");
			return objectListing.getNextMarker();
		}
		return null;
	}
	public static boolean download(List<String> keys, String localDir) {
		if(null==keys || keys.isEmpty()) {
			return false;
		}
		boolean success = false;
		for(String key : keys) {
			 if(OssUtils.download(key, localDir)) {
				 logger.info("Success to download a file[" + key + "]");
				 success = true;
			 } else {
				 logger.warn("Failed to download a file[" + key + "]");
				 success = false;
				 break;
			}
		}
		return success;
	}
	
	public static String load(String logFileName) {
		if(null==logFileName || "".equals(logFileName)) {
			return null;
		}
		File logFile = new File(logFileName);
		if(!logFile.exists() || logFile.isDirectory()) {
			return null;
		}
		RandomAccessFile rf = null;  
		try {
			String flagStr = "Success to convert nextMarker[";
		    rf = new RandomAccessFile(logFile, "r");  
		    long len = rf.length();  
		    long start = rf.getFilePointer();  
		    long nextend = start + len - 1;  
		    String line = "";
		    if(-1 == nextend) {
		    	return null;
		    }
		    rf.seek(nextend);
		    int c = -1;  
		    while (nextend > start) {  
		        c = rf.read();  
		        if (c == '\n' || c == '\r') {  
		            line = rf.readLine();
		            //[2017-04-17 20:03:05 154] < INFO > : Success to download a file[2017_04_17/00C4DC7AE6ED9DF732CAA31A3B292CF4#10162.txt]
		            if (null != line) {
		            	if(line.contains(flagStr)) {
							int beginIndex = line.indexOf(flagStr);
							if(-1 != beginIndex) {
								beginIndex = beginIndex + flagStr.length();
								int endIndex = line.indexOf("]", beginIndex);
								return line.substring(beginIndex, endIndex);
							}
						}
		            }
		            nextend--;
		        }
		        nextend--;  
		        rf.seek(nextend);  
		        if (nextend == 0) {// 当文件指针退至文件开始处，输出第一行  
		            System.out.println(rf.readLine());  
		        }  
		    }
		} catch (FileNotFoundException e) {  
			e.printStackTrace();  
		} catch (IOException e) {  
			e.printStackTrace();  
		} finally {  
		    try {  
		        if (null != rf) {
		        	rf.close();  
		        }
		    } catch (IOException e) {  
		        e.printStackTrace();  
		    }  
		}
		return null;
	}
	
}
